package com.example.ecommerce.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.ecommerce.dto.RoleDTO;
import com.example.ecommerce.entity.Role;
import com.example.ecommerce.exception.BusinessException;
import com.example.ecommerce.mapper.RoleMapper;
import com.example.ecommerce.service.MenuService;
import com.example.ecommerce.service.RoleService;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional(rollbackFor = Exception.class)
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    @Autowired
    private RoleMapper roleMapper;
    
    @Autowired
    private MenuService menuService;
    
    @Autowired
    private ModelMapper modelMapper;

    @Override
    public RoleDTO getRoleById(Long id) {
        Role role = getById(id);
        if (role == null) {
            throw new BusinessException("角色不存在");
        }
        
        RoleDTO roleDTO = modelMapper.map(role, RoleDTO.class);
        // 获取角色的菜单ID列表
        roleDTO.setMenuIds(getRoleMenuIds(id));
        
        return roleDTO;
    }

    @Override
    public Page<RoleDTO> getRoleList(Integer page, Integer size, String keyword) {
        Page<Role> rolePage = new Page<>(page, size);
        
        // 构建查询条件
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.hasText(keyword)) {
            queryWrapper.like(Role::getName, keyword);
        }

        // 执行分页查询
        Page<Role> result = roleMapper.selectPage(rolePage, queryWrapper);
        
        // 转换为DTO
        List<RoleDTO> roleDTOs = result.getRecords().stream()
                .map(role -> {
                    RoleDTO dto = modelMapper.map(role, RoleDTO.class);
                    dto.setMenuIds(getRoleMenuIds(role.getId()));
                    return dto;
                })
                .collect(Collectors.toList());
        
        Page<RoleDTO> dtoPage = new Page<>(result.getCurrent(), result.getSize(), result.getTotal());
        dtoPage.setRecords(roleDTOs);
        
        return dtoPage;
    }

    @Override
    public RoleDTO createRole(RoleDTO roleDTO) {
        // 验证角色名称是否重复
        if (checkNameExists(roleDTO.getName(), null)) {
            throw new BusinessException("角色名称已存在");
        }
        
//        // 验证角色编码是否重复
//        if (checkCodeExists(roleDTO.getCode(), null)) {
//            throw new BusinessException("角色编码已存在");
//        }
        
        Role role = modelMapper.map(roleDTO, Role.class);
//        role.setCreatedAt(LocalDateTime.now());
//        role.setUpdatedAt(LocalDateTime.now());
        
        // 保存角色
        save(role);
        
        // 分配菜单权限
        if (roleDTO.getMenuIds() != null && !roleDTO.getMenuIds().isEmpty()) {
            assignMenus(role.getId(), roleDTO.getMenuIds());
        }
        
        return getRoleById(role.getId());
    }

    @Override
    public RoleDTO updateRole(Long id, RoleDTO roleDTO) {
        Role existingRole = getById(id);
        if (existingRole == null) {
            throw new BusinessException("角色不存在");
        }
        
        // 验证角色名称是否重复
        if (!existingRole.getName().equals(roleDTO.getName()) && 
                checkNameExists(roleDTO.getName(), id)) {
            throw new BusinessException("角色名称已存在");
        }
        
        // 验证角色编码是否重复
//        if (!existingRole.getCode().equals(roleDTO.getCode()) &&
//                checkCodeExists(roleDTO.getCode(), id)) {
//            throw new BusinessException("角色编码已存在");
//        }
        
        Role role = modelMapper.map(roleDTO, Role.class);
        role.setId(id);
//        role.setUpdatedAt(LocalDateTime.now());
        
        // 更新角色
        updateById(role);
        
        // 更新菜单权限
        if (roleDTO.getMenuIds() != null) {
            assignMenus(id, roleDTO.getMenuIds());
        }
        
        return getRoleById(id);
    }

    @Override
    public void deleteRole(Long id) {
        if (!exists(id)) {
            throw new BusinessException("角色不存在");
        }
        
        // 检查是否有用户使用该角色
        Integer userCount = roleMapper.countUsersByRoleId(id);
        if (userCount > 0) {
            throw new BusinessException("该角色下存在用户，无法删除");
        }
        
        // 删除角色菜单关系
        roleMapper.deleteRoleMenus(id);
        
        // 删除角色
        removeById(id);
    }

    @Override
    public List<RoleDTO> getAllRoles() {
        List<Role> roles = list(new LambdaQueryWrapper<Role>()
                .eq(Role::getStatus, 1)
                .orderByAsc(Role::getSort));

        return roles.stream()
                .map(role -> modelMapper.map(role, RoleDTO.class))
                .collect(Collectors.toList());
    }

    @Override
    public void assignMenus(Long roleId, List<Long> menuIds) {
        if (!exists(roleId)) {
            throw new BusinessException("角色不存在");
        }
        
        // 验证菜单是否都存在
        if (menuIds != null && !menuIds.isEmpty()) {
            for (Long menuId : menuIds) {
                if (!menuService.exists(menuId)) {
                    throw new BusinessException("菜单不存在: " + menuId);
                }
            }
        }
        
        // 删除原有的角色菜单关系
        roleMapper.deleteRoleMenus(roleId);
        
        // 保存新的角色菜单关系
        if (menuIds != null && !menuIds.isEmpty()) {
            roleMapper.insertRoleMenus(roleId, menuIds);
        }
    }

    @Override
    public List<Long> getRoleMenuIds(Long roleId) {
        return roleMapper.selectMenuIdsByRoleId(roleId);
    }

    @Override
    public List<RoleDTO> getRolesByUserId(Long userId) {
        List<Role> roles = list(new LambdaQueryWrapper<Role>()
                .inSql(Role::getId, 
                        "SELECT role_id FROM UserRoles WHERE user_id = " + userId )
                .eq(Role::getStatus, 1)
                .orderByAsc(Role::getSort));
        
        return roles.stream()
                .map(role -> modelMapper.map(role, RoleDTO.class))
                .collect(Collectors.toList());
    }

    @Override
    public boolean exists(Long id) {
        return getById(id) != null;
    }

    private boolean checkNameExists(String name, Long excludeId) {
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Role::getName, name);
        if (excludeId != null) {
            queryWrapper.ne(Role::getId, excludeId);
        }
        return count(queryWrapper) > 0;
    }

}